#include "modbustest.h"
#include <QDebug>
using namespace Moolink;

QByteArray ModbusTest::getReadCmd(Device *device,int funCode)
{
    QByteArray ba=device->protocol.toLatin1();
    const char *protocol_char=ba.data();
    QMetaEnum metaEnum=QMetaEnum::fromType<protocolList>();
    protocolList proInt=protocolList(metaEnum.keyToValue(protocol_char));

    int datatype=1234;//3412//

//    int funCode=3;
    int regAddr=0;
    int regLength=2;



    //crcValue=calculateCRC(data(), size()) == checksum<quint16>();
    //QString crcStr;
    //crcStr=sprintf("%02X",(addrStr.at(0).toLatin1()+addrStr.at(1)+'R'+'D')%255);
    //01 03 00 00 00 02 C4 0B

    uchar temp[2];
    QByteArray cmdByte;
    cmdByte[0]=device->comAddr%256;
    cmdByte[1]=funCode%256;

    qToBigEndian<quint16>(regAddr, temp);
    cmdByte.append((char*)temp,2);

    qToBigEndian<quint16>(regLength, temp);
    cmdByte.append((char*)temp,2);


    QByteArray cmdStr;
    quint16 crcValue;
    quint8 lrcValue;
    switch (proInt) {
    case RTU:
        //RTU两字节CRC校验码

        crcValue=calculateCRC(cmdByte, cmdByte.size());
        temp[0]=crcValue/256;
        temp[1]=crcValue%256;
        cmdByte.append((char*)temp,2);

        return cmdByte;
        break;
    case ASCII:

        //ASCII单字节LRC校验码

        lrcValue=calculateLRC(cmdByte, cmdByte.size());
        temp[0]=lrcValue;
        cmdByte.append((char*)temp,1);

        cmdStr=cmdByte.toHex().toUpper();
        cmdStr.prepend(':');
        cmdStr.append('\r');
        cmdStr.append('\n');

        return cmdStr;
        break;
    case CODmax:
        //RTU两字节CRC校验码
        crcValue=calculateCRC(cmdByte, cmdByte.size());
        temp[0]=crcValue/256;
        temp[1]=crcValue%256;
        cmdByte.append((char*)temp,2);

        return cmdByte;
        break;
    default:
        cmdStr[0]=0;
        break;
    }
    //qDebug()<<proInt;
    return cmdStr;//tprotocol;//cmdStr;
}



QString ModbusTest::getDataResultStr(Device *device,QByteArray responseData)
{
    QString recvData;
    QByteArray ba=device->protocol.toLatin1();
    const char *protocol_char=ba.data();
    QMetaEnum metaEnum=QMetaEnum::fromType<protocolList>();
    protocolList proInt=protocolList(metaEnum.keyToValue(protocol_char));

    QString ResultStr="";

    QString addrStr;
    addrStr.sprintf("%02X",device->comAddr);

    QString rtdVal;
    QString crcStr;
    QString lrcStr;
    QByteArray dataarry;
    QString datastr;
    int hex;
    float b;
    switch (proInt) {
    case RTU:
            recvData = QString::fromLatin1(responseData.toHex()).toUpper();
            if(!recvData.startsWith(addrStr)) {ResultStr="addr Error:"+recvData;  return ResultStr;}

            crcStr.sprintf("%04X",calculateCRC(responseData,responseData.size()-2));
            if(!recvData.endsWith(crcStr)) {ResultStr="CRC Error:"+recvData;  return ResultStr;}
        break;
    case ASCII:
            addrStr.sprintf("%02X",device->comAddr);
            recvData = QString::fromLatin1(responseData).toUpper();
            if(!recvData.startsWith(":"+addrStr)) {ResultStr=":slaveId Error!";  return ResultStr;} else responseData.remove(0,1);
            if(!recvData.endsWith("\r\n")) {ResultStr="\\r\\n Error!";  return ResultStr;} else {responseData.remove(responseData.size()-2,2); recvData.chop(2);};

            lrcStr.sprintf("%02X",calculateLRC(responseData,responseData.size()-2));
            if(!recvData.endsWith(lrcStr)) {ResultStr="LRC Error:"+recvData;}

            //if(!recvData.endsWith(crcStr+"\r")) {ResultStr="Crc or \\r Error:"+recvData;  return ResultStr;}
        break;
    case CODmax:
        recvData = QString::fromLatin1(responseData.toHex()).toUpper();
        if(!recvData.startsWith(addrStr)) {ResultStr="addr Error:"+recvData;  return ResultStr;}

        crcStr.sprintf("%04X",calculateCRC(responseData,responseData.size()-2));
        if(!recvData.endsWith(crcStr)) {ResultStr="CRC Error:"+recvData;  return ResultStr;}
        //
        dataarry.append(responseData.at(5));
        dataarry.append(responseData.at(6));
        dataarry.append(responseData.at(3));
        dataarry.append(responseData.at(4));

        datastr=dataarry.toHex();
        hex =datastr.toInt(0,16);
        b=*(float*)&hex;

        for(int i=0;i<device->deviceCodes.size();i++)
        {
                if(device->deviceCodes.at(i)->code.startsWith("w01018"))
                {
                    rtdVal=HJ212::formatNumber(device->deviceCodes.at(i)->dataFormat,b);
                    device->deviceCodes.at(i)->cpData["Rtd"]=rtdVal;
                    device->deviceCodes.at(i)->cpData["RtdFlag"]=dataFlagNormal;
                    device->deviceCodes.at(i)->dataFlag=dataFlagNormal;
                    device->deviceCodes.at(i)->dataString="Rtd:"+rtdVal+" "+device->deviceCodes.at(i)->unit;
                }
                else
                {
                    device->deviceCodes.at(i)->dataString="无法装载数据,请确认所绑定的设备支持本因子代码!";
                }
        }
        qDebug()<<HJ212::formatNumber("N5.1",b);




        break;

    default:
            ResultStr="No Type To Process!";
        break;
    }

//    pvStr.sprintf("%.2f",recvData.mid(5,6).toFloat()/100);
//    svStr.sprintf("%d",recvData.mid(11,11).toInt());


    //qDebug()<<crcStr;

    //qDebug()<<proInt;
//    device->cpData[device->code+"-Rtd"]=pvStr;
//    device->cpData[device->code+"-Cou"]=svStr;
//    ResultStr="Rtd:"+pvStr+" "+device->unit+", Cou:"+svStr+" "+device->unitTotal;
    ResultStr=recvData;
    device->dataFlag=dataFlagNormal;
    return ResultStr;//tprotocol;//cmdStr;

}



quint8 ModbusTest::calculateLRC(const char *data, qint32 len)
{
    quint32 lrc = 0;
    while (len--)
        lrc += *data++;
    return -(quint8(lrc));
}



quint16 ModbusTest::calculateCRC(const char *data, qint32 len)
{
    // Generated by pycrc v0.8.3, https://pycrc.org
    // Width = 16, Poly = 0x8005, XorIn = 0xffff, ReflectIn = True,
    // XorOut = 0x0000, ReflectOut = True, Algorithm = bit-by-bit-fast

    quint16 crc = 0xFFFF;
    while (len--) {
        const quint8 c = *data++;
        for (qint32 i = 0x01; i & 0xFF; i <<= 1) {
            bool bit = crc & 0x8000;
            if (c & i)
                bit = !bit;
            crc <<= 1;
            if (bit)
                crc ^= 0x8005;
        }
        crc &= 0xFFFF;
    }


    crc = crc_reflect(crc & 0xFFFF, 16) ^ 0x0000;
    return (crc >> 8) | (crc << 8); // swap bytes
}



//inline static QByteArray create(Type type, int serverAddress, const QModbusPdu &pdu,
//                                char delimiter = '\n') {
//    QByteArray result;
//    QDataStream out(&result, QIODevice::WriteOnly);
//    out << quint8(serverAddress) << pdu;

//    if (type == Ascii) {
//        out << calculateLRC(result, result.size());
//        return ":" + result.toHex() + "\r" + delimiter;
//    } else {
//        out << calculateCRC(result, result.size());
//    }
//    return result;
//}


